﻿
#include "Plane.h"

#include <Riccsson/Xna/Framework/BoundingBox.h>
#include <Riccsson/Xna/Framework/BoundingSphere.h>
#include <Riccsson/Xna/Framework/BoundingFrustum.h>

using namespace Riccsson::System;
using namespace Riccsson::Xna::Framework;

// PlaneHelper.

float PlaneHelper::ClassifyPoint(Vector3 ref point, Plane ref plane)
{
	return point.X * plane.Normal.X + point.Y * plane.Normal.Y + point.Z * plane.Normal.Z + plane.D;
}
float PlaneHelper::PerpendicularDistance(Vector3 ref point, Plane ref plane)
{
	// dist = (ax + by + cz + d) / sqrt(a*a + b*b + c*c)
	return (float)Riccsson::System::Math::Abs((plane.Normal.X * point.X + plane.Normal.Y * point.Y + plane.Normal.Z * point.Z)
		/ Riccsson::System::Math::Sqrt(plane.Normal.X * plane.Normal.X + plane.Normal.Y * plane.Normal.Y + plane.Normal.Z * plane.Normal.Z));
}

// Plane.

Plane::Plane()
{
    D = 0;
}
Plane::Plane(Vector4 value)
{
	Normal = Vector3(value.X, value.Y, value.Z);
    D = value.W;
}
Plane::Plane(Vector3 normal, float d)
{
    Normal = normal;
    D = d;
}
Plane::Plane(Vector3 a, Vector3 b, Vector3 c)
{
    Vector3 ab = b - a;
    Vector3 ac = c - a;

    Vector3 cross = Vector3::Cross(ab, ac);
    Normal = Vector3::Normalize(cross);
    D = -(Vector3::Dot(Normal, a));
}
Plane::Plane(float a, float b, float c, float d)
{
	Normal = Vector3(a, b, c);
    D = d;
}
float Plane::Dot(Vector4 value)
{
    return ((((this->Normal.X * value.X) + (this->Normal.Y * value.Y)) + (this->Normal.Z * value.Z)) + (this->D * value.W));
}
void Plane::Dot(Vector4 ref value, float out result)
{
    result = (((this->Normal.X * value.X) + (this->Normal.Y * value.Y)) + (this->Normal.Z * value.Z)) + (this->D * value.W);
}
float Plane::DotCoordinate(Vector3 value)
{
    return ((((this->Normal.X * value.X) + (this->Normal.Y * value.Y)) + (this->Normal.Z * value.Z)) + this->D);
}
void Plane::DotCoordinate(Vector3 ref value, float out result)
{
    result = (((this->Normal.X * value.X) + (this->Normal.Y * value.Y)) + (this->Normal.Z * value.Z)) + this->D;
}
float Plane::DotNormal(Vector3 value)
{
    return (((this->Normal.X * value.X) + (this->Normal.Y * value.Y)) + (this->Normal.Z * value.Z));
}
void Plane::DotNormal(Vector3 ref value, float out result)
{
    result = ((this->Normal.X * value.X) + (this->Normal.Y * value.Y)) + (this->Normal.Z * value.Z);
}
void Plane::Transform(Plane ref plane, Quaternion ref rotation, Plane out result)
{
    throw Riccsson::System::NotImplementedException();
}
void Plane::Transform(Plane ref plane, Matrix ref matrix, Plane out result)
{
    throw Riccsson::System::NotImplementedException();
}
Plane Plane::Transform(Plane plane, Quaternion rotation)
{
    throw Riccsson::System::NotImplementedException();
}
Plane Plane::Transform(Plane plane, Matrix matrix)
{
    throw Riccsson::System::NotImplementedException();
}
void Plane::Normalize()
{
	float factor;
	Vector3 normal = Normal;
	Normal = Vector3::Normalize(Normal);
	factor = (float)Riccsson::System::Math::Sqrt(Normal.X * Normal.X + Normal.Y * Normal.Y + Normal.Z * Normal.Z) / 
			(float)Riccsson::System::Math::Sqrt(normal.X * normal.X + normal.Y * normal.Y + normal.Z * normal.Z);
	D = D * factor;
}
Plane Plane::Normalize(Plane value)
{
	Plane ret;
	Normalize(/*ref*/ value, /*out*/ ret);
	return ret;
}
void Plane::Normalize(Plane ref value, Plane out result)
{
	float factor;
	result.Normal = Vector3::Normalize(value.Normal);
	factor = (float)Riccsson::System::Math::Sqrt(result.Normal.X * result.Normal.X + result.Normal.Y * result.Normal.Y + result.Normal.Z * result.Normal.Z) / 
			(float)Riccsson::System::Math::Sqrt(value.Normal.X * value.Normal.X + value.Normal.Y * value.Normal.Y + value.Normal.Z * value.Normal.Z);
	result.D = value.D * factor;
}
bool Plane::Equals(Riccsson::System::object* other)
{
    return (instanceof(other, Plane)) ? this->Equals((Plane*)other) : false;
}
bool Plane::Equals(Plane* other)
{
    return ((Normal == other->Normal) && (D == other->D));
}
int Plane::GetHashCode()
{
    //return Normal.GetHashCode() ^ D.GetHashCode();
	throw;
}
PlaneIntersectionType Plane::Intersects(BoundingBox& box)
{
    return box.Intersects(*this);
}
void Plane::Intersects(BoundingBox ref box, PlaneIntersectionType out result)
{
    box.Intersects (/*ref*/ *this, /*out*/ result);
}
PlaneIntersectionType Plane::Intersects(BoundingFrustum& frustum)
{
    return frustum.Intersects(*this);
}
PlaneIntersectionType Plane::Intersects(BoundingSphere& sphere)
{
    return sphere.Intersects(*this);
}
void Plane::Intersects(BoundingSphere ref sphere, PlaneIntersectionType out result)
{
    sphere.Intersects(/*ref*/ *this, /*out*/ result);
}
GC_PTR<Riccsson::System::string> Plane::ToString()
{
    //return string::Format("{{Normal:{0} D:{1}}}", Normal, D);
	throw;
}